package component.group;

import java.util.*;

import javax.media.j3d.Transform3D;

import component.*;
import component.traverse.TraverseListener;

public class ComponentGroup implements TraverseListener {
	public static final Integer SELECT = 0;
	public static final Integer DESELECT = 1;
	
	private final Set<AbstractComponent> components = new HashSet<AbstractComponent>();
	
	public ComponentGroup() {
		
	}
	
	public ComponentGroup(ComponentGroup base) {
		this.add(base);
	}
	
	public void add(AbstractComponent component) {
		components.add(component);
	}
	
	public void remove(AbstractComponent component) {
		components.remove(component);
	}
	
	public void add(ComponentGroup group) {
		components.addAll(group.components);
	}
	
	public void remove(ComponentGroup group) {
		components.removeAll(group.components);
	}
	
	public void clear() {
		components.clear();
	}
	
	public Collection<AbstractComponent> getComponents() {
		return Collections.unmodifiableSet(components);
	}
	
	public boolean isEmpty() {
		return components.isEmpty();
	}
	
	public int size() {
		return components.size();
	}

	public boolean contains(AbstractComponent component) {
		return components.contains(component);
	}
	
	public boolean isLocked() {
		for (AbstractComponent c : components) {
			if (c.isLocked()) return true;
		}
		return false;
	}
	
	public boolean isDirectlyConnected(AbstractComponent component) {
		if (contains(component)) return true;
		Iterator<AbstractComponent> it = components.iterator();
		while(it.hasNext()) {
			if(it.next().getConnectedComponents().contains(component)) {
				return true;
			}
		}
		return false;
	}
	
	public void setStatus(int status) {
		for (AbstractComponent c : components) {
			c.setStatus(status);
		}
	}
	
	public void setStatusFlag(int flag, boolean status) {
		for (AbstractComponent c : components) {
			c.setStatus(flag, status);
		}		
	}

	@Override
	public boolean traverseNode(AbstractComponent component, Object command) {
		if (SELECT.equals(command)) {
			this.add(component);
		} else if (DESELECT.equals(command)) {
			this.remove(component);
		}
		return true;
	}
	
	public boolean containsLockedComponents() {
		for (AbstractComponent c : components) {
			if (c.isLocked())
				return true;
		}
		return false;
	}

	public void applyTransform(Transform3D transform) {
		if (containsLockedComponents()) {
			throw new RuntimeException("Trying to apply a transform to a locked group.");
		}
		for (AbstractComponent c : components)
			c.applyTransform(transform);
	}
	
	public boolean isValidPosition() {
		for (AbstractComponent c : components) {
			if (!c.isValidPosition()) {
				return false;
			}
		}
		return true;
	}
	
	public void disposeAll() {
		for (AbstractComponent c : components) {
			c.dispose();
		}
		components.clear();
	}

	public void unlockAll() {
		for (AbstractComponent c : components) {
			c.unlock();
		}
	}
	
	public void lockAll() {
		for (AbstractComponent c : components) {
			c.lock();
		}		
	}
	
	public boolean hasRoot() {
		for (AbstractComponent c : components) {
			if (c.isRoot())
				return true;
		}
		return false;
	}
	
	public void promoteToRoot() {
		for (AbstractComponent c : components) {
			c.setRoot(true);
		}
	}
	
	public void removeRoot() {
		for (AbstractComponent c : components) {
			c.setRoot(false);
		}
	}

}
